package com.taobao.txc.sample;

import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.Producer;
import com.aliyun.openservices.ons.api.SendResult;
import com.taobao.txc.client.aop.annotation.TxcTransaction;
import com.taobao.txc.common.TxcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

@Service
public class BizService implements InitializingBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(BizService.class);

    private static final String TOPIC = "gts-test-topic";

    @Autowired
    private Producer txcMQProducer;

    @Autowired
    private JdbcTemplate jdbcTemplateA;

    @Autowired
    private JdbcTemplate jdbcTemplateB;

    @TxcTransaction
    public void doTransfer(int money) {
        LOGGER.info("GTS Transaction Begins: " + TxcContext.getCurrentXid());

        // 1. 从数据源 A 的帐户扣款
        jdbcTemplateA.update("update user_money_a set money = money - ? where id = ?", money, Application.ACCOUNT_A_ID);

        // 2. 发 MQ 消息
        Message message = new Message();
        message.setTopic(TOPIC);
        message.setBody(String.valueOf(money).getBytes());
        String messageId = null;
        try {
            SendResult r = txcMQProducer.send(message);
            messageId = r.getMessageId();
            LOGGER.info("Send Message ID[" + messageId + "]");
        } catch (Throwable e) {
            throw new RuntimeException("Failed to send MQ message", e);
        }

        // 3. 从数据源 B 的帐户存款
        jdbcTemplateB.update("update user_money_b set money = money + ? where id = ?", money, Application.ACCOUNT_B_ID);

        // Check if it's balance
        int balanceA = jdbcTemplateA.queryForObject("select money from user_money_a where id = ?", java.lang.Integer.class, Application.ACCOUNT_A_ID);
        int balanceB = jdbcTemplateA.queryForObject("select money from user_money_b where id = ?", java.lang.Integer.class, Application.ACCOUNT_B_ID);
        LOGGER.info("Let's check! A: " + balanceA + "   B: " + balanceB + "   total：" + (balanceA + balanceB));

        // 余额不足时抛异常，GTS会回滚前两次操作
        if (balanceA < 0) {
            throw new RuntimeException("Not Enough Money. MQ Message ID[" + messageId + "] will be cancelled. ");
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        try {
            txcMQProducer.start();
            LOGGER.info("MQ Producer is started.");
        } catch (Throwable e) {
            throw new RuntimeException("Failed to start MQ Producer", e);
        }
    }
}
